package cn.iocoder.yudao.module.trade.service.depositorder;

import cn.iocoder.yudao.framework.common.enums.CrmUserTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.CheckUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.member.api.images.ImagesMapperApi;
import cn.iocoder.yudao.module.member.api.images.uto.ImagesDOVO;
import cn.iocoder.yudao.module.member.api.user.CrmMemberUserApi;
import cn.iocoder.yudao.module.member.api.user.dto.CrmMemberUserRespDTO;
import cn.iocoder.yudao.module.product.api.cylinder.CylinderTypeMapperApi;
import cn.iocoder.yudao.module.product.api.packaging.PackagingMapperApi;
import cn.iocoder.yudao.module.product.api.packaging.dto.PackagingDTO;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.trade.controller.admin.depositorder.vo.DepositOrderPageReqVO;
import cn.iocoder.yudao.module.trade.controller.admin.depositorder.vo.DepositOrderRespVO;
import cn.iocoder.yudao.module.trade.controller.admin.depositorder.vo.DepositOrderSaveReqVO;
import cn.iocoder.yudao.module.trade.controller.admin.depositorderreturn.vo.DepositOrderReturnRespVO;
import cn.iocoder.yudao.module.trade.controller.admin.depositorderreturnlog.vo.DepositOrderReturnLogRespVO;
import cn.iocoder.yudao.module.trade.convert.depositorder.DepositOrderConvert;
import cn.iocoder.yudao.module.trade.dal.dataobject.depositorder.DepositOrderDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.depositorderreturnlog.DepositOrderReturnLogDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.depositproductrelation.DepositProductRelationDO;
import cn.iocoder.yudao.module.trade.dal.mysql.depositorder.DepositOrderMapper;
import cn.iocoder.yudao.module.trade.dal.mysql.depositorderreturnlog.DepositOrderReturnLogMapper;
import cn.iocoder.yudao.module.trade.dal.mysql.depositproductrelation.DepositProductRelationMapper;
import cn.iocoder.yudao.module.trade.service.depositorderreturn.DepositOrderReturnService;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;

/**
 * 押金信息 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
@Slf4j
public class DepositOrderServiceImpl implements DepositOrderService {

    @Resource
    private DepositOrderMapper depositOrderMapper;
    @Resource
    private DepositProductRelationMapper depositProductRelationMapper;
    @Resource
    private ImagesMapperApi imagesMapperApi;
    @Resource
    private PackagingMapperApi packagingMapperApi;
    @Resource
    private DeptApi deptApi;
    @Resource
    private CrmMemberUserApi crmMemberUserApi;
    @Resource
    private CylinderTypeMapperApi cylinderTypeMapperApi;
    @Resource
    private DepositOrderReturnService depositOrderReturnService;
    @Resource
    private DepositOrderReturnLogMapper depositOrderReturnLogMapper;
    @Resource
    private AdminUserApi adminUserApi;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createDepositOrder(DepositOrderSaveReqVO createReqVO) {
        // 插入
        DepositOrderDO depositOrder = BeanUtils.toBean(createReqVO, DepositOrderDO.class);
        List<DepositProductRelationDO> doList = createReqVO.getRelationDOList();
        // 设置剩余数量
        depositOrder.setResidueCount(doList.stream().collect(Collectors.summingInt(DepositProductRelationDO::getSkuCount)));
        depositOrderMapper.insert(depositOrder);
        // 押金关系
        doList.forEach(x -> {
            // 校验押金 / 租金 的上限下限
            PackagingDTO pacDTO = validateDepositOrderPriceConf(x);


            x.setCreateTime(LocalDateTime.now());

            x.setDepositId(depositOrder.getId());
            x.setProductTypeId(pacDTO.getCylinderId());
            x.setSkuName(pacDTO.getSpuName());

        });
        depositProductRelationMapper.insertBatch(doList);
        // 图片记录
        if (StringUtils.isNotEmpty(createReqVO.getImageLink())){
            List<String> imgList = Arrays.asList(createReqVO.getImageLink().split(","));
            List<ImagesDOVO> list = new ArrayList<>();
            imgList.forEach(x -> {
                ImagesDOVO imagesDO = new ImagesDOVO();
                imagesDO.setImageLink(x);
                imagesDO.setThirdId(depositOrder.getId());
                imagesDO.setUseType("1");
                imagesDO.setCreateTime(LocalDateTime.now());
                list.add(imagesDO);
            });
            imagesMapperApi.insertImagsList(list);
        }
        // 返回
        return depositOrder.getId();
    }

    // 校验押金 / 租金 的上限下限
    private PackagingDTO validateDepositOrderPriceConf(DepositProductRelationDO dto) {
        PackagingDTO packaging = packagingMapperApi.selectByPackagingDto(dto.getSkuId());
        // 押金超过上限
        if (null != packaging.getDepositUpperPr() && dto.getDeposit().compareTo(packaging.getDepositUpperPr()) > 0){
            throw exception(DEPOSIT_ORDER_PRICE_DEPOSIT_UPPER, packaging.getDepositUpperPr());
        }
        // 押金低于下限
        if (null != packaging.getDepositLowerPr() && dto.getDeposit().compareTo(packaging.getDepositLowerPr()) < 0){
            throw exception(DEPOSIT_ORDER_PRICE_OEPOSIT_LOWER, packaging.getDepositLowerPr());
        }

        // 如果收取租金
        if (dto.getIsRent() == 0) {
            // 租金超过上限
            if (null != packaging.getRentUpperPr() && dto.getRentUnitPrice().compareTo(packaging.getRentUpperPr()) > 0){
                throw exception(DEPOSIT_ORDER_RENT_UPPER, packaging.getRentUpperPr());
            }
            // 租金低于下限
            if (null != packaging.getRentLowerPr() && dto.getRentUnitPrice().compareTo(packaging.getRentLowerPr()) < 0){
                throw exception(DEPOSIT_ORDER_RENT_LOWER, packaging.getRentLowerPr());
            }

        }
        return packaging;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateDepositOrder(DepositOrderSaveReqVO updateReqVO) {
        // 校验存在
        validateDepositOrderExists(updateReqVO.getId());
        // 更新
        DepositOrderDO updateObj = BeanUtils.toBean(updateReqVO, DepositOrderDO.class);

        // 更新钢瓶记录  押金关系表
        if (CollectionUtils.isNotEmpty(updateReqVO.getRelationDOList())){

            List<DepositProductRelationDO> doList = updateReqVO.getRelationDOList();
            // 更新押金 默认的剩余数量
            updateObj.setResidueCount(doList.stream().collect(Collectors.summingInt(DepositProductRelationDO::getSkuCount)));

            doList.forEach(x -> {
                PackagingDTO pacDTO = validateDepositOrderPriceConf(x);
                x.setProductTypeId(pacDTO.getCylinderId());
                x.setDepositId(updateReqVO.getId());
                x.setSkuName(pacDTO.getSpuName());
            });
            depositProductRelationMapper.insertOrUpdateBatch(doList);

        }
        // 更新附件/ 图片
        if (StringUtils.isNotEmpty(updateReqVO.getImageLink())) {
            List<String> imgList = Arrays.asList(updateReqVO.getImageLink().split(","));
            List<ImagesDOVO> list = new ArrayList<>();
            imgList.forEach(x -> {
                ImagesDOVO imagesDO = new ImagesDOVO();
                imagesDO.setImageLink(x);
                imagesDO.setUseType("1");
                imagesDO.setCreateTime(LocalDateTime.now());
                list.add(imagesDO);
            });
            imagesMapperApi.updateImagesList(list);
        }
        depositOrderMapper.updateById(updateObj);
    }

    @Override
    public void deleteDepositOrder(Long id) {
        // 校验存在
        validateDepositOrderExists(id);
        // 删除
        DepositOrderDO orderDO = new DepositOrderDO().setId(id);
        orderDO.setDeleted(Boolean.TRUE);
        depositOrderMapper.updateById(orderDO);
//        depositOrderMapper.deleteById(id);
    }

    private void validateDepositOrderExists(Long id) {
        if (depositOrderMapper.selectById(id) == null) {
            throw exception(DEPOSIT_ORDER_NOT_EXISTS);
        }
    }

    @Override
    public DepositOrderRespVO getDepositOrder(Long id) {
        DepositOrderDO depositOrderDO = depositOrderMapper.selectById(id);
        DepositOrderRespVO orderRespVO = BeanUtils.toBean(depositOrderDO, DepositOrderRespVO.class);
        orderRespVO.setDeptName(deptApi.getDept(orderRespVO.getDeptId()).getName());
        LambdaQueryWrapperX<DepositProductRelationDO> wrapperX = new LambdaQueryWrapperX<>();
        wrapperX.eq(DepositProductRelationDO::getDepositId, id);
        //    钢瓶信息
        List<DepositProductRelationDO> relationDOS = depositProductRelationMapper.selectList(wrapperX);
        orderRespVO.setRelationDOS(CollectionUtils.isEmpty(relationDOS) ? new ArrayList<>() : relationDOS);
        // 上传图片路径
        orderRespVO.setImageLink(imagesMapperApi.selectByCrmMemberUserId(id));
        CrmMemberUserRespDTO member = crmMemberUserApi.getCrmMemberById(depositOrderDO.getCrmMemberUserId());
        log.info("getDepositOrder member:"+ JSON.toJSONString(member));
        orderRespVO.setCrmName(member.getName());
        orderRespVO.setCrmCard(member.getIdNumber());
        orderRespVO.setCrmMobile(member.getMobile());
        orderRespVO.setCrmAddress(member.getDetailAddress());
        orderRespVO.setCrmCode(member.getCode());
        orderRespVO.setReturnRespVOSlist(new ArrayList<>());
        return orderRespVO;
    }

    @Override
    public DepositOrderRespVO getDepositOrderAndRelanReturn(Long id) {

        DepositOrderDO depositOrderDO = depositOrderMapper.selectById(id);
        DepositOrderRespVO orderRespVO = BeanUtils.toBean(depositOrderDO, DepositOrderRespVO.class);
        orderRespVO.setRemark(null);
        orderRespVO.setDesipotRemark(depositOrderDO.getRemark());
        CrmMemberUserRespDTO member = crmMemberUserApi.getCrmMemberById(depositOrderDO.getCrmMemberUserId());

        orderRespVO.setCrmName(member.getName());
        orderRespVO.setCrmCard(member.getIdNumber());
        orderRespVO.setCrmMobile(member.getMobile());
        orderRespVO.setCrmAddress(member.getDetailAddress());
        orderRespVO.setCrmCode(member.getCode());

        //设置默认值
        orderRespVO.setBottleReturnCount(0);


        // 查询退瓶记录
        List<DepositOrderReturnRespVO> list = depositOrderReturnService.getDepositOrderReturnByDepositId(id, null);

        if (CollectionUtils.isNotEmpty(list)) {
            list.forEach(x -> {
                x.setCreator( adminUserApi.getUser(Long.valueOf(x.getCreator())).getNickname());
                LambdaQueryWrapperX<DepositOrderReturnLogDO> wrapper = new LambdaQueryWrapperX<>();
                wrapper.eq(DepositOrderReturnLogDO ::getReturnId, x.getId() );
                List<DepositOrderReturnLogDO> logDOList = depositOrderReturnLogMapper.selectList(wrapper);
                List<String> list2 = new ArrayList<>();
                logDOList.forEach(y -> {
                    Long cylinderId = packagingMapperApi.selectByPackagingDto(y.getSkuId()).getCylinderId();
                    list2.add(cylinderTypeMapperApi.getCylinderTypeById(cylinderId).getModelCode());
                });
                List<DepositOrderReturnLogRespVO> returnLogRespVOS = BeanUtils.toBean(logDOList, DepositOrderReturnLogRespVO.class);

                x.setReturnLogList(CollectionUtils.isNotEmpty(returnLogRespVOS) ? returnLogRespVOS : new ArrayList<>());
                x.setCylinderCode(list2.stream().distinct().collect(Collectors.toList()));
            });
            // 设置总押瓶数
            orderRespVO.setSteelCylinderTotal(list.get(0).getSteelCylinderTotal());
            // 设置已退瓶数
            orderRespVO.setBottleReturned(list.stream().filter(x -> x.getStatus() == 1).collect(Collectors.summingInt(DepositOrderReturnRespVO::getBottleReturnCount)));

        } else {
            // 设置总押瓶数
            orderRespVO.setSteelCylinderTotal(depositOrderDO.getResidueCount());
        }
        LambdaQueryWrapperX<DepositProductRelationDO> wrapperX = new LambdaQueryWrapperX<>();
        wrapperX.eq(DepositProductRelationDO::getDepositId, id);
        wrapperX.eq(DepositProductRelationDO::getStatus, 0);
        //    钢瓶信息
        List<DepositProductRelationDO> relationDOS = depositProductRelationMapper.selectList(wrapperX);
        if (CollectionUtils.isNotEmpty(relationDOS)) {
            relationDOS.forEach(x -> {
                x.setRefundableNum(x.getSkuCount() - (x.getBottleReturnCount() == null ? 0 : x.getBottleReturnCount()));
            });
            orderRespVO.setRelationDOS(relationDOS);
        }
        orderRespVO.setReturnRespVOSlist(CollectionUtils.isNotEmpty(list) ? list : new ArrayList<>());

        return orderRespVO;
    }
    @Override
    public DepositOrderRespVO getDepositOrderAndRelanReturnLog(Long id) {

        DepositOrderDO depositOrderDO = depositOrderMapper.selectById(id);
        DepositOrderRespVO orderRespVO = BeanUtils.toBean(depositOrderDO, DepositOrderRespVO.class);

        CrmMemberUserRespDTO member = crmMemberUserApi.getCrmMemberById(depositOrderDO.getCrmMemberUserId());

        orderRespVO.setCrmName(member.getName());
        orderRespVO.setCrmCard(member.getIdNumber());
        orderRespVO.setCrmMobile(member.getMobile());
        orderRespVO.setCrmAddress(member.getDetailAddress());
        orderRespVO.setCrmCode(member.getCode());



        // 查询退瓶记录
        List<DepositOrderReturnRespVO> list = depositOrderReturnService.getDepositOrderReturnByDepositId(id, null);
        List<DepositOrderReturnLogRespVO> returnLog= new ArrayList<>();
        if (CollectionUtils.isNotEmpty(list)) {
            list.forEach(x -> {
                x.setConfirmName(x.getConfirmId() == null ? null : adminUserApi.getUser(x.getConfirmId()).getNickname());
                LambdaQueryWrapperX<DepositOrderReturnLogDO> wrapper = new LambdaQueryWrapperX<>();
                wrapper.eq(DepositOrderReturnLogDO ::getReturnId, x.getId() );
                List<DepositOrderReturnLogDO> logDOList = depositOrderReturnLogMapper.selectList(wrapper);
                List<DepositOrderReturnLogRespVO> returnLogRespVOS = BeanUtils.toBean(logDOList, DepositOrderReturnLogRespVO.class);

                returnLogRespVOS.forEach(y -> {
                    Long cylinderId = packagingMapperApi.selectByPackagingDto(y.getSkuId()).getCylinderId();
                    y.setCylinderCode(cylinderTypeMapperApi.getCylinderTypeById(cylinderId).getModelCode());
                    y.setReturnOrderCode(x.getCode());
                    y.setStatus(x.getStatus());
                    y.setConfirmName(x.getConfirmName());
                    y.setConfirmTime(x.getConfirmTime());
                    y.setCreator( adminUserApi.getUser(Long.valueOf(y.getCreator())).getNickname());
                });
                returnLog.addAll(returnLogRespVOS);
            });
            orderRespVO.setReturnLog(returnLog);
            //设置已退瓶数
            orderRespVO.setBottleReturned(list.stream().filter(x -> x.getStatus() == 1).collect(Collectors.summingInt(DepositOrderReturnRespVO::getBottleReturnCount)));
        }

        return orderRespVO;
    }

    @Override
    public List<DepositOrderDO> getDepositOrderList(Long userId) {
        LambdaQueryWrapperX<DepositOrderDO> queryWrapperX = new LambdaQueryWrapperX<>();
        queryWrapperX.eq(DepositOrderDO::getCrmMemberUserId,userId);
        queryWrapperX.eq(DepositOrderDO::getStatus,0);
        return depositOrderMapper.selectList(queryWrapperX);
    }

    @Override
    public PageResult<DepositOrderPageReqVO> getDepositOrderPage(DepositOrderPageReqVO pageReqVO) {
        List<CrmMemberUserRespDTO> crmList = null;
        // 新加业务 需求：与燃气户关联
        if (StringUtils.isNotEmpty(pageReqVO.getCrmCode()) || StringUtils.isNotEmpty(pageReqVO.getCrmName()) || StringUtils.isNotEmpty(pageReqVO.getCrmMobile())
                                || null != pageReqVO.getCrmType()) {
            CrmMemberUserRespDTO respDTO = new CrmMemberUserRespDTO();
            respDTO.setName(pageReqVO.getCrmName());
            respDTO.setMobile(pageReqVO.getCrmMobile());
            respDTO.setCode(pageReqVO.getCrmCode());
            respDTO.setAccountType(Integer.parseInt(pageReqVO.getCrmType()));
            List<CrmMemberUserRespDTO> list = crmMemberUserApi.selectCrmList(respDTO);
            crmList.addAll(list);

        }

        //获取燃气户id合集 用于查询押金单
        if (CollectionUtils.isNotEmpty(crmList)) {
            pageReqVO.setCrmIds(crmList.stream().map(CrmMemberUserRespDTO::getId).distinct().collect(Collectors.toList()));
        }
        PageResult<DepositOrderDO> page = depositOrderMapper.selectPage(pageReqVO);

        PageResult<DepositOrderPageReqVO> result = new PageResult<>(DepositOrderConvert.INSTANCE.convertList(page.getList()), (long) page.getList().size());

        List<DepositOrderPageReqVO> list = result.getList();
        if (CollectionUtils.isEmpty(list)){
            return result;
        }
        list.forEach(x -> {
            //所属机构
            x.setDeptName(deptApi.getDept(x.getDeptId()).getName());
            // 查询钢瓶和押金关系表信息
            List<DepositProductRelationDO> relationDOList = depositProductRelationMapper.selectListByDepostId(x.getId());
            if (CollectionUtils.isEmpty(relationDOList)){
                return;
            }
            // 押瓶数量
            x.setDeposiCount(relationDOList.stream().mapToInt(DepositProductRelationDO ::getSkuCount).sum());
            // 押金规格
            x.setModelCodes(relationDOList.stream().map(DepositProductRelationDO ::getModelCode).collect(Collectors.toList()));
            // 租金单价
            x.setDepositPrices(relationDOList.stream().map(DepositProductRelationDO ::getDeposit).collect(Collectors.toList()));
            // 押金登记时间
            x.setDepositTimes(relationDOList.stream().map(DepositProductRelationDO ::getDepositTimes).collect(Collectors.toList()));
            // 是否租
            x.setIsRents(relationDOList.stream().map(DepositProductRelationDO ::getIsRent).collect(Collectors.toList()));

            // 设置押金单对应燃气户的信息
            CrmMemberUserRespDTO dto = crmMemberUserApi.getCrmMemberById(x.getCrmMemberUserId());
            x.setCrmCode(dto.getCode());
            x.setCrmName(dto.getName());
            x.setCrmMobile(dto.getMobile());
            x.setCrmType(String.valueOf(dto.getAccountType()));
//            x.setCrmType(CrmUserTypeEnum.valueOf(dto.getAccountType()).getName());
            x.setCrmCard(dto.getIdNumber());
            x.setCrmAddress(dto.getDetailAddress());
        });

        return result;
    }

}
